#ifndef CHARACTER_HPP_
#define CHARACTER_HPP_

#include <LinearMath\btVector3.h>
#include <OGRE\OgreMesh.h>
#include <OGRE/OgreAnimationState.h>
#include "BulletDynamics/Character/btKinematicCharacterController.h"

#define NUM_ANIMS 13           // number of animations the character has
#define CHAR_HEIGHT 5          // height of character's center of mass above ground
#define CAM_HEIGHT 2           // height of camera above character's center of mass
#define RUN_SPEED 17           // character running speed in units per second
#define TURN_SPEED 500.0f      // character turning in degrees per second
#define ANIM_FADE_SPEED 7.5f   // animation crossfade speed in % of full weight per second
#define JUMP_ACCEL 100.0f       // character jump acceleration in upward units per squared second
#define GRAVITY 5.0f          // gravity in downward units per squared second
	
enum AnimID
{
	ANIM_IDLE_BASE,
	ANIM_IDLE_TOP,
	ANIM_RUN_BASE,
	ANIM_RUN_TOP,
	ANIM_HANDS_CLOSED,
	ANIM_HANDS_RELAXED,
	ANIM_DRAW_SWORDS,
	ANIM_SLICE_VERTICAL,
	ANIM_SLICE_HORIZONTAL,
	ANIM_DANCE,
	ANIM_JUMP_START,
	ANIM_JUMP_LOOP,
	ANIM_JUMP_END,
	ANIM_NONE
};

namespace Ogre {
	class SceneManager;
	class Entity;
	class ManualObject;
	class ParticleSystem;
	class AnimationState;
}

class btSoftRigidDynamicsWorld;
class btRigidBody;
class btSoftBody;
struct btSoftBodyWorldInfo;

class PlayState;

enum CharacterStates { CS_NONE = 0, CS_SOLID, CS_LIQUID, CS_GAS };

typedef struct
{
	float kpr,		// Pressure coefficient [-inf,+inf]
		kdp,		// Damping coefficient [0,1]
		kdf,		// Dynamic friction coefficient [0,1]
		mklst;		// Linear stiffness coefficient [0,1]
} BlobShapeParams;

class Character
{
	public:
		//---------Bleh---------
		void setBaseAnimation(AnimID id, bool reset = false)
		{
			if (mBaseAnimID >= 0 && mBaseAnimID < NUM_ANIMS)
			{
				// if we have an old animation, fade it out
				mFadingIn[mBaseAnimID] = false;
				mFadingOut[mBaseAnimID] = true;
			}

			mBaseAnimID = id;

			if (id != ANIM_NONE)
			{
				// if we have a new animation, enable it and fade it in
				mAnims[id]->setEnabled(true);
				mAnims[id]->setWeight(0);
				mFadingOut[id] = false;
				mFadingIn[id] = true;
				if (reset) mAnims[id]->setTimePosition(0);
			}
		}

		void setTopAnimation(AnimID id, bool reset = false)
		{
			if (mTopAnimID >= 0 && mTopAnimID < NUM_ANIMS)
			{
				// if we have an old animation, fade it out
				mFadingIn[mTopAnimID] = false;
				mFadingOut[mTopAnimID] = true;
			}

			mTopAnimID = id;
			if (id != ANIM_NONE)
			{
				// if we have a new animation, enable it and fade it in
				mAnims[id]->setEnabled(true);
				mAnims[id]->setWeight(0);
				mFadingOut[id] = false;
				mFadingIn[id] = true;
				if (reset) mAnims[id]->setTimePosition(0);
			}
		}


		//----------------------

		//---Sinbad character---
		void fadeAnimations(float dt);
		Ogre::AnimationState*				mAnims[NUM_ANIMS];    // master animation list
		//void setTopAnimation(AnimID id, bool reset = false);
		//void setBaseAnimation(AnimID id, bool reset = false);
		AnimID								mBaseAnimID;                   // current base (full- or lower-body) animation
		AnimID								mTopAnimID;                    // current top (upper-body) animation
		bool								mFadingIn[NUM_ANIMS];            // which animations are fading in
		bool								mFadingOut[NUM_ANIMS];           // which animations are fading out
		bool								mSwordsDrawn;
		Ogre::Vector3						forwardVector;
		float mTimer;                // general timer to see how long animations have been playing
		//----------------------


		Character(Ogre::SceneManager* scene, btSoftRigidDynamicsWorld* world, btSoftBodyWorldInfo* sbworldinfo);

		void changeState(int state);
		void applyForce(float x, float y, float z);

		void setPosition(const btVector3& pos);

		//This method constructs the blob form
		//We need to be able to do this during runtime when a setPosition call
		//is made
		void createBlobForm(const BlobShapeParams& bsp, const btVector3& startPos);
		//only call init() on character after the entities/bodies have been created
		void init();
		//possible use for animation between states
		void update(float dt, Ogre::SceneNode* m_pCameraNode, Ogre::Vector3 forwardVector);

		int getState() { return m_State; }
		bool isFalling();

		friend class PlayState;
		btRigidBody*						m_SolidBody;
		btPairCachingGhostObject*			m_SolidGhostObject;
		btSoftBody*							m_LiquidBody;
		btRigidBody*						m_GasBody;
	private:
		btVector3 calculateBlobCenter();

		Ogre::SceneManager*					m_pScene;
		btSoftRigidDynamicsWorld*			m_pPhysicsWorld;
		btSoftBodyWorldInfo*				m_SoftBodyWorldInfo;
		int									m_State;
		
		Ogre::Entity*						m_SolidEntity;
		Ogre::ParticleSystem*				m_GasPS;
		//manual object replaces the liquid body's entity
		//Ogre::Entity*						m_BlobEntity;
		Ogre::ManualObject*					m_ManualObject;

		//Bullet CharacterDemo
		btKinematicCharacterController*		m_SolidCharacterController;
		//----
		double								m_OldY;

		BlobShapeParams						m_BSP;
		btVector3							m_Position;
};


#endif